package com.kaixinff.kaixin001.servlet;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.kaixinff.kaixin001.util.Filter;
import com.kaixinff.kaixin001.util.KXClient;
import com.kaixinff.kaixin001.util.KXUtil;
import com.kaixinff.kaixin001.util.RegStep;
import com.kaixinff.name.User;
import com.kaixinff.net.HttpClient;
import com.kaixinff.net.NameValuePair;

@SuppressWarnings("serial")
public class AddFriendsServlet extends HttpServlet {
	private static final String SYS_URL = KXUtil.HOST_URL + "/msg/sys.php?type=1";
	private static String allGroups;
	private static final int MAX_THREAD = 9;
	private static Map<String, String> email2uid;
	private static List<String> users;
	private static int i = 0;
	private static int j = 1;
	
	private byte[] lock = new byte[0];
	private TreeMap<Integer, String> buffer = new TreeMap<Integer, String>();
	private int num = 0;
	
	private static Map<String, String> getEmail2uid() throws IOException {
		if (email2uid == null) {
			email2uid = new HashMap<String, String>();
			Properties properties = KXUtil.getUid2Email();
			for (Enumeration<Object> e = properties.keys(); e.hasMoreElements(); ) {
				String uid = (String) e.nextElement();
				String email = properties.getProperty(uid);
				email2uid.put(email, uid);
			}
		}
		return email2uid;
	}
	
	public void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws IOException {
		resp.setContentType("text/html; charset=" + KXUtil.CHARSET);
		if (users == null) {
			List<User> userList = KXUtil.getUsers(new Filter(){
				@Override
				public boolean access(User user) {
					return user.hasStep(RegStep.ADD_FRIEND_CONFIRM);
				}}, resp);
			if (userList == null) {
				return;
			} else {
				users = new ArrayList<String>();
				for (User u : userList) {
					users.add(u.getId());
				}
			}
		}
		int n = users.size();
		if (i >= n) {
			i = 0;
			j++;
		}
		if (j >= (n  + 1) / 2) {
			return;
		}
		resp.getWriter().println("<form name='form' method='post' action='/kx/addfriends'>");
		resp.getWriter().println("<h1>+" + j + "</h1>");
		buffer = new TreeMap<Integer, String>();
		num = MAX_THREAD;
		for (int k = 0; k < MAX_THREAD; k++) {
			new SubThread().start();
		}
		synchronized (lock) {
			while (num > 0) {
				try {
					lock.wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}							
			}
		}
		for (Iterator<String> it = buffer.values().iterator(); it.hasNext(); ) {
			resp.getWriter().println(it.next());
		}
		resp.getWriter().println("<input type=submit name='submit' value='go'>");
		resp.getWriter().println("</form>");
	}
	
	public void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws IOException {
		String[] cookiekeys = req.getParameterValues("cookiekey");
		if (cookiekeys != null) {
			String[] uids = req.getParameterValues("uid");
			String[] emails = req.getParameterValues("email");
			String[] rcodes = req.getParameterValues("rcode");
			String[] codes = req.getParameterValues("code");
			num = cookiekeys.length;
			for (int i = 0, n = cookiekeys.length; i < n; i++) {
				KXClient client = KXClient.getInstance(cookiekeys[i]);
				new SubThread(client, uids[i], emails[i], rcodes[i], codes[i]).start();
			}
			synchronized (lock) {
				while (num > 0) {
					try {
						lock.wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}							
				}
			}
		}
		doGet(req, resp);
	}
	
	public class SubThread extends Thread {
		private KXClient client;
		private String uid;
		private String email;
		private String rcode;
		private String code;
		
		public SubThread() {
		}
		
		public SubThread(KXClient client, String uid, String email, String rcode, String code) {
			this.client = client;
			this.uid = uid;
			this.rcode = rcode;
			this.code = code;
			this.email = email;
		}
		
		public void run() {
			if (rcode == null && code ==null) {
				boolean ignore = true;
				while (ignore) {
					boolean result = init();
					if (result) {
						try {
							ignore = get();
						} catch (IOException e) {
							e.printStackTrace();
						}
					} else {
						ignore = false;
					}
					if (!ignore) {
						exit();
					}
				}
			} else {
				boolean result = false;
				try {
					result = post();
				} catch (IOException e) {
					e.printStackTrace();
				}
				synchronized (lock) {
					num --;
					if (!result) {
						i -= MAX_THREAD;
					}
					lock.notify();
				}
			}
		}
		
		private boolean init() {
			synchronized (lock) {
				int n = users.size();
				if (i >= n) {
					return false;
				}
				try {
					client = KXClient.getInstance(users.get((i) % n));
					email = users.get((i + j) % n);
					uid = getEmail2uid().get(email);
					i++;
				} catch (IOException e) {
					e.printStackTrace();
					return false;
				}
			}
			return true;
		}
		
		private void exit() {
			synchronized (lock) {
				num --;
				lock.notify();
			}
		}
		
		private boolean get() throws IOException {
			if (!isFriend()) {
				boolean result = addFriend();
				if (result) {
					return result;
				}
				String rcode = Math.random() + "_" + System.currentTimeMillis();
				String imgUrl = "/interface/createwavecaptcha.php?norect=1&randnum="
						+ rcode + "&cookiekey=" + client.getEmail();
				synchronized (buffer) {
					int index = users.indexOf(client.getEmail()) + 1;
					StringBuffer sb = new StringBuffer();
					sb.append("<input type=hidden name='cookiekey' value='" + client.getEmail() + "'>" + index + ": "  + client.getEmail());
					sb.append("<input type=hidden name='uid' value='" + uid + "'>");
					sb.append("<input type=hidden name='email' value='" + email + "'> + " + email);
					sb.append("<input type=hidden name='rcode' value='" + rcode + "'>");
					sb.append("<input type=text name='code' value=''>");
					sb.append("<img src='" + imgUrl + "' /><br>");
					buffer.put(index, sb.toString());
				}
				return false;
			} else {
				return true;
			}
		}
		
		private boolean isFriend() throws IOException {
			String url = KXUtil.HOST_URL + "/friend/editorder.php";
			String html = client.doGet(url, null).getContent();
			Pattern p = Pattern.compile("\"uid\":\"(\\d+?)\",");
			Matcher m = p.matcher(html);
			while (m.find()) {
				String key = m.group(1);
				if (key.equals(uid)) {
					return true;
				}
			}
			return false;
		}
		
		private boolean addFriend() throws IOException {
			String url = "http://www.kaixin001.com/home/?uid=" + uid;
			String cont = client.doGet(url, null).getContent();
			Pattern p = Pattern.compile("<div [^<>]*?style=\"[^<>]*display:(\\w+?);[^<>]*\"><a [^<>]*?href=\"[^<>]+?\"[^<>]*>加为好友</a></div>");
			Matcher m = p.matcher(cont);
			boolean isFriend = false;
			if (m.find()) {
				isFriend = m.group(1).equals("none");
			}
			if (!isFriend) {
				String addUrl = "http://www.kaixin001.com/friend/new.php?touid=" + uid;
				String html = client.doGet(addUrl, url).getContent();
				p = Pattern.compile("var flag = parseInt[(]\"(\\d+?)\"[)];");
				m = p.matcher(html);
				if (m.find()) {
					int flag = Integer.parseInt(m.group(1));
					if (flag == 0) {
						return post();
					}
				}
				return false;
			}
			return true;
		}
		
		private boolean post() throws IOException {
			String referer = "http://www.kaixin001.com/friend/new.php?touid=" + uid;
			String url = "http://www.kaixin001.com/friend/addverify.php";
			List<NameValuePair> params = new ArrayList<NameValuePair>();
			params.add(new NameValuePair("from", ""));
			params.add(new NameValuePair("touid", uid));
			params.add(new NameValuePair("content", "hello"));
			if (rcode != null) {
				params.add(new NameValuePair("rcode", rcode));
				params.add(new NameValuePair("code", code));
			}
			params.add(new NameValuePair("usercode", ""));
			params.add(new NameValuePair("email", ""));
			params.add(new NameValuePair("bidirection", ""));
			String html = client.doPost(url, referer, params.toArray(new NameValuePair[]{})).getContent();
			if (html.indexOf("好友请求已发送成功!") > -1) {
				System.out.println("好友请求已发送成功: " + email);
				KXClient client2 = KXClient.getInstance(email);
				synchronized (client2) {
					confirm(client2);
				}
				return true;
			}
			return false;
		}
		
		private void confirm(KXClient client) throws IOException {
			String html = client.doGet(SYS_URL, null).getContent();
			String[] strs = html.split("<div class=\"l\"><b>好友请求：</b></div>");
			Pattern p = Pattern.compile("javascript[:]agreefriend[(](\\d+?), (\\d+?)[)];");
			for (int i = 0, n = strs.length; i < n; i++) {
				if (strs[i].indexOf("“hello”") > -1) {
					Matcher m = p.matcher(strs[i]);
					if (m.find()) {
						String fuid = m.group(1);
						String smid = m.group(2);
						confirm(client, fuid, smid);
					}
				}
			}
		}
		
		private void confirm(KXClient client, String fuid, String smid) throws IOException {
			String url = KXUtil.HOST_URL + "/friend/editfriend.php";
			NameValuePair[] params = new NameValuePair[]{
					new NameValuePair("fuid", fuid),
					new NameValuePair("byname", ""),
					new NameValuePair("memo", ""),
					new NameValuePair("groups", ""),
					new NameValuePair("allgroups", getAllGroups(client, fuid, smid)),
					new NameValuePair("start", "0"),
					new NameValuePair("sysmsgtype", "1"),
					new NameValuePair("from", "sysmsg"),
					new NameValuePair("smid", smid)};
			client.doPost(url, SYS_URL, params);
			System.out.println("好友请求已通过：" + client.getEmail());
			url = KXUtil.HOST_URL + "/msg/sysdel.php";
			params = new NameValuePair[]{
					new NameValuePair("smid", smid),
					new NameValuePair("start", "0")};
			client.doPost(url, SYS_URL, params);
		}
		
		private String getAllGroups(HttpClient client, String fuid, String smid) throws IOException {
			if (allGroups == null) {
				String url = KXUtil.HOST_URL + "/friend/editfriend_dialog.php?smid=" + smid + "&fuid=" + fuid;
				String html = client.doGet(url, SYS_URL).getContent();
				Pattern p = Pattern.compile("[{]\"checked\"[:]\".+?\",\"type\"[:]\".+?\",\"name\"[:]\"(.+?)\"[}]");
				Matcher m = p.matcher(html);
				StringBuffer sb = new StringBuffer();
				while (m.find()) {
					String group = KXUtil.toUTF(m.group(1));
					sb.append(",");
					sb.append(group);
				}
				allGroups = sb.substring(1);
			}
			return allGroups;
		}
	}
}
